<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="keywords" content="Hexo Theme Keep">
    <meta name="description" content="Hexo Theme Keep">
    <meta name="author" content="jianyu">
    
    <title>
        
            Kaios:分析usb Mode切换,状态变化的底层逻辑 |
        
        gyu&#39;s 时光
    </title>
    
<link rel="stylesheet" href="/css/style.css">

    <link rel="shortcut icon" href="/images/logo.svg">
    
<link rel="stylesheet" href="/css/font-awesome.min.css">

    <script id="hexo-configurations">
    let KEEP = window.KEEP || {};
    KEEP.hexo_config = {"hostname":"gyu.gitee.io","root":"/","language":"zh-CN","path":"search.xml"};
    KEEP.theme_config = {"toc":{"enable":true,"number":true,"expand_all":true,"init_open":true},"style":{"primary_color":"#0066CC","avatar":"https://cdn.jsdelivr.net/gh/XPoet/image-hosting@master/common-use/avatar.jpg","favicon":"/images/logo.svg","article_img_align":"left","left_side_width":"260px","content_max_width":"920px","hover":{"shadow":true,"scale":false},"first_screen":{"enable":true,"background_img":"/images/bg.svg","description":"只要开始，一切都来得及."},"scroll":{"progress_bar":{"enable":true},"percent":{"enable":true}}},"local_search":{"enable":true,"preload":true},"code_copy":{"enable":true,"style":"default"},"pjax":{"enable":false},"lazyload":{"enable":false},"version":"3.4.2"};
    KEEP.language_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 月前","year":"%s 年前"};
  </script>
<meta name="generator" content="Hexo 5.4.0"></head>


<body>
<div class="progress-bar-container">
    
        <span class="scroll-progress-bar"></span>
    

    
</div>


<main class="page-container">

    

    <div class="page-main-content">

        <div class="page-main-content-top">
            <header class="header-wrapper">

    <div class="header-content">
        <div class="left">
            <a class="logo-title" href="/">
                gyu&#39;s 时光
            </a>
        </div>

        <div class="right">
            <div class="pc">
                <ul class="menu-list">
                    
                        <li class="menu-item">
                            <a class=""
                               href="/"
                            >
                                首页
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/archives"
                            >
                                归档
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/categories"
                            >
                                分类
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/tags"
                            >
                                标签
                            </a>
                        </li>
                    
                    
                        <li class="menu-item search search-popup-trigger">
                            <i class="fas fa-search"></i>
                        </li>
                    
                </ul>
            </div>
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fas fa-search"></i></div>
                
                <div class="icon-item menu-bar">
                    <div class="menu-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <div class="header-drawer">
        <ul class="drawer-menu-list">
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/">首页</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/archives">归档</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/categories">分类</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/tags">标签</a>
                </li>
            
        </ul>
    </div>

    <div class="window-mask"></div>

</header>


        </div>

        <div class="page-main-content-middle">

            <div class="main-content">

                
                    <div class="fade-in-down-animation">
    <div class="article-content-container">

        <div class="article-title">
            <span class="title-hover-animation">Kaios:分析usb Mode切换,状态变化的底层逻辑</span>
        </div>

        
            <div class="article-header">
                <div class="avatar">
                    <img src="https://cdn.jsdelivr.net/gh/XPoet/image-hosting@master/common-use/avatar.jpg">
                </div>
                <div class="info">
                    <div class="author">
                        <span class="name">jianyu</span>
                        
                            <span class="author-label">Engineer</span>
                        
                    </div>
                    <div class="meta-info">
                        <div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fas fa-edit"></i>&nbsp;2021-05-05 12:10:32
    </span>
    
        <span class="article-categories article-meta-item">
            <i class="fas fa-folder"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/categories/Kaios/">Kaios</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fas fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/gecko/">gecko</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
</div>

                    </div>
                </div>
            </div>
        

        <div class="article-content markdown-body">
            <h3 id="一．首先了解一下什么是Netlink和Uevent"><a href="#一．首先了解一下什么是Netlink和Uevent" class="headerlink" title="一．首先了解一下什么是Netlink和Uevent"></a>一．首先了解一下什么是Netlink和Uevent</h3><ul>
<li><p>详细可参考：<a class="link"   target="_blank" rel="noopener" href="https://www.kancloud.cn/alex_wsc/android_depp/412996" >https://www.kancloud.cn/alex_wsc/android_depp/412996<i class="fas fa-external-link-alt"></i></a><br>这里简单描述一下：</p>
<p>  １. Netlink是Linux系统中一种用户空间进程和Kernel进行通信的机制，通过这个机制，位于用户空间的进程，可接收来自Kernel的一些信息（例如Vold中用到的USB或SD的插拔消息），同时应用层也可通过Netlink向Kernel发送一些控制命令。</p>
<p>  ２. UEvent，全称User Space Event，是kernel通知用户空间的一种机制；<br>在Android中很多地方使用到了UEvent机制．(比如SD  USB 的插拔事件)</p>
</li>
</ul>
<p>像HDMI，Battery，USB相关等；当我们需要接受底层的UEvent的时候，我们就需要注册一个<code>UEventObserver</code>，上层是如何处理这一过程的呢？来看看先：</p>
<ul>
<li>Android上处理逻辑： <a class="link"   target="_blank" rel="noopener" href="https://blog.csdn.net/u011006622/article/details/53392427" >https://blog.csdn.net/u011006622/article/details/53392427<i class="fas fa-external-link-alt"></i></a></li>
</ul>
<p><strong>Kaios主要处理逻辑</strong>: gecko层将<code>usbstatuschange</code>的消息Notify给app层．<br>app层监听到usb状态改变的消息，通过判断<code>deviceAttached</code>，<code>deviceConfigured</code>的值，从而来show　Dialog弹出框，实现usb插入的选择usb mode的功能．<br>(了解：Kaios系统中gecko层,相当与Android的Framework 层.内容不尽相同)</p>
<ul>
<li>gecko/dom/usb/UsbManager.cpp</li>
</ul>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">#define USB_STATUS_CHANGE_NAME NS_LITERAL_STRING(&quot;usbstatuschange&quot;)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">void</span><br><span class="line">UsbManager::Notify(const hal::UsbStatus&amp; aUsbStatus)</span><br><span class="line">&#123;</span><br><span class="line">  bool previousDeviceAttached &#x3D; mDeviceAttached;</span><br><span class="line">  bool previousDeviceConfigured &#x3D; mDeviceConfigured;</span><br><span class="line">  UpdateFromUsbStatus(aUsbStatus);</span><br><span class="line">  </span><br><span class="line">  if (previousDeviceAttached !&#x3D; mDeviceAttached ||</span><br><span class="line">      previousDeviceConfigured !&#x3D; mDeviceConfigured) &#123;</span><br><span class="line"></span><br><span class="line">		UsbEventInit init;</span><br><span class="line">		init.mDeviceAttached &#x3D; aUsbStatus.deviceAttached();</span><br><span class="line">		init.mDeviceConfigured &#x3D; aUsbStatus.deviceConfigured();</span><br><span class="line">		RefPtr&lt;UsbEvent&gt; event &#x3D; UsbEvent::Constructor(this,</span><br><span class="line">													   USB_STATUS_CHANGE_NAME,</span><br><span class="line">													   init);</span><br><span class="line">		&#x2F;&#x2F; Delay for debouncing USB disconnects.</span><br><span class="line">		&#x2F;&#x2F; We often get rapid connect&#x2F;disconnect events</span><br><span class="line">		&#x2F;&#x2F; when enabling USB functions which need debouncing.</span><br><span class="line"></span><br><span class="line">		 if (!mDeviceAttached &amp;&amp; !mDebounce) &#123;</span><br><span class="line">		  MessageLoopForIO::current()-&gt;PostDelayedTask(FROM_HERE,</span><br><span class="line">		  NewRunnableMethod(this, &amp;UsbManager::DebounceEvent), 500);&#x2F;&#x2F;500ms</span><br><span class="line">		  mDebounce &#x3D; true;</span><br><span class="line">		 return;</span><br><span class="line">	   &#125;</span><br><span class="line">     mDebounce &#x3D; false;</span><br><span class="line">      DispatchTrustedEvent(event);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="二．底层逻辑，事件的分发流程"><a href="#二．底层逻辑，事件的分发流程" class="headerlink" title="二．底层逻辑，事件的分发流程"></a>二．底层逻辑，事件的分发流程</h3><p><code>&gt; IUeventObserver当设备发生变化时，这会引起Kernel发送Uevent消息，例如设备的插入和拔出等.Kernel(包含驱动层)发送和该设备相关的Uevent消息，Hal层注册IUeventObserver code:</code></p>
<ul>
<li>gecko/hal/gonk/GonkHal.cpp</li>
</ul>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">class UsbObserver final : public IUeventObserver</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line">  NS_INLINE_DECL_REFCOUNTING(UsbObserver)</span><br><span class="line"></span><br><span class="line">  UsbObserver()</span><br><span class="line">    :mUpdater(new UsbUpdater())</span><br><span class="line">  &#123;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  virtual void Notify(const NetlinkEvent &amp;aEvent)</span><br><span class="line">  &#123;</span><br><span class="line">    &#x2F;&#x2F; this will run on IO thread</span><br><span class="line">    NetlinkEvent *event &#x3D; const_cast&lt;NetlinkEvent*&gt;(&amp;aEvent);</span><br><span class="line">    const char *subsystem &#x3D; event-&gt;getSubsystem();</span><br><span class="line">    &#x2F;&#x2F; e.g. DEVPATH&#x3D;&#x2F;devices&#x2F;virtual&#x2F;android_usb&#x2F;android0</span><br><span class="line">    const char *devpath &#x3D; event-&gt;findParam(&quot;DEVPATH&quot;);</span><br><span class="line">    if (strcmp(subsystem, &quot;android_usb&quot;) &#x3D;&#x3D; 0 &amp;&amp;</span><br><span class="line">        strstr(devpath, &quot;android_usb&quot;)) &#123;</span><br><span class="line">      NS_DispatchToMainThread(mUpdater);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">protected:</span><br><span class="line">  ~UsbObserver() &#123;&#125;</span><br><span class="line">private:</span><br><span class="line">  RefPtr&lt;UsbUpdater&gt; mUpdater;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<ul>
<li>kernel/drivers/usb/gadget/android.c<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">if (!android_class) &#123;</span><br><span class="line">	android_class &#x3D; class_create(THIS_MODULE, &quot;android_usb&quot;);</span><br><span class="line">	if (IS_ERR(android_class))</span><br><span class="line">		return PTR_ERR(android_class);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
</ul>
<p><code>kernel中 创建设备节点  /sys/devices/virtual/android_usb/android0。 并调用usb composite driver framework的 usb_composite_probe() 函数进行usb物理设备侦测； 并用 android usb driver 替换了 usb composite layer 的 初始化函数（虽然usb composite layer的初始化函数将被 android的初始化函数调用）。 android_work() 回调函数将发送 connect/disconnect uevent 到 userspace</code></p>
<p>GonkHal监听到事件之后就会分发出去，交给主线程处理，到最后会分发到<code>UsbManager::Notify</code>向app层分发<code>usbstatuschange</code>事件．</p>
<p><strong>当前遇到的问题</strong>：在settings app中开启和关闭USB　Storage.上层也会收到usbstatuschange事件，从而会有Dialog框弹出．<br><strong>Android与Kiaos的差异</strong>：Android上settings app中是没有这个选项(USB　Storage)．所以Android上不会有这个bug．Android的USB Mode弹出框在插USB的时候会弹出，然后它会隐藏到通知栏，如果下次想切换USB Mode，可以下拉通知栏，来进行操作．</p>
<p><strong>log</strong>：</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">02-08 19:32:53.539   311   311 I GeckoConsole: Content JS LOG: usb_storage: _getUsbProtocol: MTP </span><br><span class="line">02-08 19:32:53.599   311   620 I AutoMounter: Changing mode from &#39;Disable&#39; to &#39;Enable-MTP&#39;</span><br><span class="line">02-08 19:32:53.599   311   620 I AutoMounter: SetUsbFunction(mtp) sys.usb.config from &#39;diag,serial_smd,rmnet_qti_bam,adb&#39; to &#39;mtp,adb&#39;</span><br><span class="line">02-08 19:32:53.599   311   620 I AutoMounter: AutoMounter state changed from IDLE to MTP_CONFIGURING</span><br><span class="line">02-08 19:32:53.599   311   620 I AutoMounterSetting: Changing status from &#39;Disabled&#39; to &#39;Enabled&#39;</span><br><span class="line">02-08 19:32:53.669   311   311 D QLOC-OSAgent: POWERSTATE: 0</span><br><span class="line">02-08 19:32:53.669   311   311 E IzatSvc_OSObserver: I&#x2F;LocTech-Value :: Data Item Value: IS_POWER_CONNECTED: false</span><br><span class="line">02-08 19:32:54.039   311   311 I usb: UsbManager::Notify~mDeviceAttached:[0] mDebounce:[0]</span><br><span class="line"></span><br><span class="line">02-08 19:32:54.049   311   311 D QLOC-OSAgent: POWERSTATE: 1</span><br><span class="line">02-08 19:32:54.049   311   311 E IzatSvc_OSObserver: I&#x2F;LocTech-Value :: Data Item Value: IS_POWER_CONNECTED: true</span><br><span class="line">02-08 19:32:54.269   311   311 I usb: Notify~mDeviceAttached:[1] mDeviceConfigured:[1]</span><br></pre></td></tr></table></figure>
<p>开启和禁用USB　Storage的功能意思是：(enable usb storage，开启MTP［多媒体传输协议］协议)电脑端可以查看device里的图片，文件，音视频数据文件．</p>
<h3 id="三．解决方案"><a href="#三．解决方案" class="headerlink" title="三．解决方案"></a>三．解决方案</h3><p>思路：插拔usb保存usb最后的连接状态，拔掉usb,上次状态lastAttach＝false.<br>如果lastAttach＝true，说明当前处于连接状态．此时监听mAttach 为true直接return.<br>目前usb连接状态下，切换 usb storage（enable | disable）.<br>会上报三次uevent事件，相当于usb的状态从:<code>CONFIGURED -&gt; DISCONNECTED -&gt; CONNECTED -&gt; CONFIGURED</code><br> DISCONNECTED -&gt; CONNECTED -&gt; CONFIGURED这三次的事件变化都是触发<code>usbstatuschange</code>，被上层app监听处理．<br>其状态对应的DeviceAttached　DeviceConfigured为：</p>
<ul>
<li>code:gecko/hal/gonk/GonkHal.cpp<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">void</span><br><span class="line">GetCurrentUsbStatus(hal::UsbStatus* aUsbStatus)</span><br><span class="line">&#123;</span><br><span class="line">   bool success;</span><br><span class="line">   char usbStateString[16];</span><br><span class="line">  &#x2F;&#x2F; see http:&#x2F;&#x2F;androidxref.com&#x2F;6.0.1_r10&#x2F;xref&#x2F;frameworks&#x2F;base&#x2F;services&#x2F;</span><br><span class="line">  &#x2F;&#x2F;            usb&#x2F;java&#x2F;com&#x2F;android&#x2F;server&#x2F;usb&#x2F;UsbDeviceManager.java#95</span><br><span class="line">  success &#x3D; ReadSysFile(&quot;&#x2F;sys&#x2F;class&#x2F;android_usb&#x2F;android0&#x2F;state&quot;,</span><br><span class="line">                        usbStateString, sizeof(usbStateString));</span><br><span class="line">  if (success) &#123;</span><br><span class="line">    if (strcmp(usbStateString, &quot;CONNECTED&quot;) &#x3D;&#x3D; 0) &#123;</span><br><span class="line">      aUsbStatus-&gt;deviceAttached() &#x3D; true;</span><br><span class="line">      aUsbStatus-&gt;deviceConfigured() &#x3D; false;</span><br><span class="line">    &#125; else if (strcmp(usbStateString, &quot;CONFIGURED&quot;) &#x3D;&#x3D; 0) &#123;</span><br><span class="line">      aUsbStatus-&gt;deviceAttached() &#x3D; true;</span><br><span class="line">      aUsbStatus-&gt;deviceConfigured() &#x3D; true;</span><br><span class="line">    &#125; else if (strcmp(usbStateString, &quot;DISCONNECTED&quot;) &#x3D;&#x3D; 0) &#123;</span><br><span class="line">      aUsbStatus-&gt;deviceAttached() &#x3D; false;</span><br><span class="line">      aUsbStatus-&gt;deviceConfigured() &#x3D; false;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">      HAL_ERR(&quot;Unexpected usb state : %s &quot;, usbStateString);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
其中CONNECTED -&gt; CONFIGURED的事件发送到上层app后会触发弹出框．<br>整个事件的变化，其实相当于一次usb的拔掉和usb的插入流程．<br>目前的解决方案就是，如果当前是连接状态，而且Attached的值是从只前的（1-&gt;0-&gt;１)短时间内的变化，不上报，从而规避了这个bug.主要修改文件为：<pre><code>  - gecko/dom/usb/UsbManager.cpp
  - gecko/dom/usb/UsbManager.h
</code></pre>
</li>
</ul>
<p><strong>Patch如下：</strong></p>
<p>diff –git a/dom/usb/UsbManager.cpp b/dom/usb/UsbManager.cpp<br>index 8208677ebb29..d94c9e653084 100644<br>— a/dom/usb/UsbManager.cpp<br>+++ b/dom/usb/UsbManager.cpp<br>@@ -15,8 +15,26 @@</p>
<ul>
<li>We have to use macros here because our leak analysis tool things we are</li>
<li>leaking strings when we have |static const nsString|. Sad :(</li>
<li>/<br>　+#include &lt;android/log.h&gt;<br>　+#define LOGI(…) __android_log_print(ANDROID_LOG_INFO, “jianyu_usb_gecko”, <strong>VA_ARGS</strong>)<br>　 #define USB_STATUS_CHANGE_NAME NS_LITERAL_STRING(“usbstatuschange”)</li>
</ul>
<p>+static uint64_t<br>+nanosecsToMillisecs(nsecs_t nsecs)<br>+{<br>　+    return nsecs / 1000000;<br>+}<br>+<br>+static bool<br>+isSoFast(const uint64_t&amp; data)<br>　+{<br>　+    uint64_t timeNowACttMs =<br>　+        nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC));<br>　+    LOGI(“Notify~mDeviceAttached/mgjyDeviceAttached/timeNowACttMs[%llu]＿＿data:[%llu]”,timeNowACttMs,data);<br>　+    return (timeNowACttMs - data) &lt; 800;<br>+}<br>+<br>+<br> namespace mozilla {<br> namespace dom {<br> namespace usb {<br>@@ -26,6 +44,8 @@ UsbManager::UsbManager(nsPIDOMWindowInner* aWindow)<br>   , mDeviceAttached(false)<br>   , mDeviceConfigured(false)<br>   , mDebounce(false)<br>　+  , mPreDeviceAttached(false)<br>　+  , mNoAttachTime(0)<br> {<br> }</p>
<p>@@ -62,6 +82,13 @@ UsbManager::UpdateFromUsbStatus(const hal::UsbStatus&amp; aUsbStatus)<br> void<br> UsbManager::Notify(const hal::UsbStatus&amp; aUsbStatus)<br> {<br>　+LOGI(“Notify~mDeviceAttached/mPreDeviceAttached:[%d] |deviceAttached:[%d] |deviceConfigured:[%d]”,mPreDeviceAttached,aUsbStatus.deviceAttached(),aUsbStatus.deviceConfigured());<br>　+<br>　+  if(mPreDeviceAttached &amp;&amp; aUsbStatus.deviceAttached()){<br>　+    //上次连接状态是true。直接return<br>　+    return;<br>　+  }<br>　+<br>   bool previousDeviceAttached = mDeviceAttached;<br>   bool previousDeviceConfigured = mDeviceConfigured;<br>@@ -83,9 +110,20 @@ UsbManager::Notify(const hal::UsbStatus&amp; aUsbStatus)<br>       MessageLoopForIO::current()-&gt;PostDelayedTask(FROM_HERE,<br>           NewRunnableMethod(this, &amp;UsbManager::DebounceEvent), 1000);<br>       mDebounce = true;<br>　+<br>　+      uint64_t timeNowMs =nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC));<br>　+      mPreDeviceAttached = false;<br>　+      mNoAttachTime = timeNowMs;<br>       return;<br>     }<br>     mDebounce = false;<br>　+    if((mDeviceAttached || mDeviceConfigured) &amp;&amp; isSoFast(mNoAttachTime)){<br>　+<br>　+      return;<br>　+    }<br>　　+<br>　+    mPreDeviceAttached = true;<br>     DispatchTrustedEvent(event);<br>   }<br> }<br>diff –git a/dom/usb/UsbManager.h b/dom/usb/UsbManager.h<br>index 8e3655900e42..69ace97fe838 100644<br>— a/dom/usb/UsbManager.h<br>+++ b/dom/usb/UsbManager.h<br>@@ -10,6 +10,7 @@<br>　 #include “mozilla/DOMEventTargetHelper.h”<br>　#include “mozilla/Observer.h”<br>　#include “nsCycleCollectionParticipant.h”<br>　#include &lt;utils/Timers.h&gt;<br> class nsPIDOMWindowInner;<br> class nsIScriptContext;<br>@@ -72,6 +73,8 @@ private:<br>   bool  mDeviceAttached;<br>   bool  mDeviceConfigured;<br>   bool  mDebounce;<br>　+  bool  mPreDeviceAttached;<br>　+  uint64_t  mNoAttachTime;<br> };<br> } // namespace usb</p>

        </div>

        
            <div class="post-copyright-info">
                <div class="article-copyright-info-container">
    <ul>
        <li>
            版权声明：本博客所有文章除特别声明外，均采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">BY-NC-SA</a> 许可协议。转载请注明出处！
        </li>
    </ul>
</div>

            </div>
        

        
            <div class="article-nav">
                
                    <div class="article-prev">
                        <a class="prev"
                           rel="prev"
                           href="/2021/06/08/Kaios%20PowerManager%20API%E8%AF%A6%E8%A7%A3/"
                        >
                            <span class="left arrow-icon flex-center">
                              <i class="fas fa-chevron-left"></i>
                            </span>
                            <span class="title flex-center">
                                <span class="post-nav-title-item">Kaios PowerManager API详解</span>
                                <span class="post-nav-item">上一篇</span>
                            </span>
                        </a>
                    </div>
                
                
                    <div class="article-next">
                        <a class="next"
                           rel="next"
                           href="/2021/04/05/Minidump%E7%9A%84%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/"
                        >
                            <span class="title flex-center">
                                <span class="post-nav-title-item">Minidump的使用技巧</span>
                                <span class="post-nav-item">下一篇</span>
                            </span>
                            <span class="right arrow-icon flex-center">
                              <i class="fas fa-chevron-right"></i>
                            </span>
                        </a>
                    </div>
                
            </div>
        

        
    </div>
</div>


                
            </div>

        </div>

        <div class="page-main-content-bottom">
            <footer class="footer">
    <div class="info-container">
        <div class="copyright-info info-item">
            &copy;
            
              <span>2018</span>&nbsp;-&nbsp;
            
            2021&nbsp;<i class="fas fa-heart icon-animate"></i>&nbsp;<a href="/">jianyu</a>
        </div>
        
        
    </div>
</footer>

        </div>
    </div>

    
        <div class="post-tools">
            <div class="post-tools-container">
    <ul class="tools-list">
        <!-- TOC aside toggle -->
        
            <li class="tools-item page-aside-toggle">
                <i class="fas fa-outdent"></i>
            </li>
        

        <!-- go comment -->
        
    </ul>
</div>

        </div>
    

    <div class="right-bottom-side-tools">
        <div class="side-tools-container">
    <ul class="side-tools-list">
        <li class="tools-item tool-font-adjust-plus flex-center">
            <i class="fas fa-search-plus"></i>
        </li>

        <li class="tools-item tool-font-adjust-minus flex-center">
            <i class="fas fa-search-minus"></i>
        </li>

        <li class="tools-item tool-expand-width flex-center">
            <i class="fas fa-arrows-alt-h"></i>
        </li>

        <li class="tools-item tool-dark-light-toggle flex-center">
            <i class="fas fa-moon"></i>
        </li>

        <!-- rss -->
        

        

        <li class="tools-item tool-scroll-to-bottom flex-center">
            <i class="fas fa-arrow-down"></i>
        </li>
    </ul>

    <ul class="exposed-tools-list">
        <li class="tools-item tool-toggle-show flex-center">
            <i class="fas fa-cog fa-spin"></i>
        </li>
        
            <li class="tools-item tool-scroll-to-top flex-center">
                <i class="arrow-up fas fa-arrow-up"></i>
                <span class="percent"></span>
            </li>
        
    </ul>
</div>

    </div>

    
        <aside class="page-aside">
            <div class="post-toc-wrap">
    <div class="post-toc">
        <ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%80%EF%BC%8E%E9%A6%96%E5%85%88%E4%BA%86%E8%A7%A3%E4%B8%80%E4%B8%8B%E4%BB%80%E4%B9%88%E6%98%AFNetlink%E5%92%8CUevent"><span class="nav-number">1.</span> <span class="nav-text">一．首先了解一下什么是Netlink和Uevent</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%BA%8C%EF%BC%8E%E5%BA%95%E5%B1%82%E9%80%BB%E8%BE%91%EF%BC%8C%E4%BA%8B%E4%BB%B6%E7%9A%84%E5%88%86%E5%8F%91%E6%B5%81%E7%A8%8B"><span class="nav-number">2.</span> <span class="nav-text">二．底层逻辑，事件的分发流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%89%EF%BC%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88"><span class="nav-number">3.</span> <span class="nav-text">三．解决方案</span></a></li></ol>
    </div>
</div>
        </aside>
    

    <div class="image-viewer-container">
    <img src="">
</div>


    
        <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
          <span class="search-input-field-pre">
            <i class="fas fa-keyboard"></i>
          </span>
            <div class="search-input-container">
                <input autocomplete="off"
                       autocorrect="off"
                       autocapitalize="off"
                       placeholder="搜索..."
                       spellcheck="false"
                       type="search"
                       class="search-input"
                >
            </div>
            <span class="popup-btn-close">
                <i class="fas fa-times"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fas fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>

    

</main>




<script src="/js/utils.js"></script>

<script src="/js/main.js"></script>

<script src="/js/header-shrink.js"></script>

<script src="/js/back2top.js"></script>

<script src="/js/dark-light-toggle.js"></script>



    
<script src="/js/local-search.js"></script>




    
<script src="/js/code-copy.js"></script>





<div class="post-scripts">
    
        
<script src="/js/left-side-toggle.js"></script>

<script src="/js/libs/anime.min.js"></script>

<script src="/js/toc.js"></script>

    
</div>



</body>
</html>
